home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Snippets / Interapplication Communication / AE Interaction Sample ƒ / sender.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-07-15  |  19.5 KB  |  536 lines  |  [TEXT/MPS ]

  1. /* Sender and Reciever are simple AppleEvent programs that demonstrate */
  2. /* all the permutations of interaction levels for sending */
  3. /* and recieving APpleEvents. */
  4. /* Have fun with them. */
  5. /*  P.S. This also uses PBCatSearch, so I've done the typing for you if you've wanted */
  6. /* to use this call but have been confused by the param block */
  7. /* C.K. Haun */
  8. /* Apple DTS */
  9. /* this sends the simple event */
  10.  
  11.  
  12. #include <Types.h>
  13. #include <memory.h>
  14. #include <Packages.h>
  15. #include <Errors.h>
  16. #include <quickdraw.h>
  17. #include <fonts.h>
  18. #include <dialogs.h>
  19. #include <windows.h>
  20. #include <menus.h>
  21. #include <events.h>
  22. #include <OSEvents.h>
  23. #include <Desk.h>
  24. #include <diskinit.h>
  25. #include <OSUtils.h>
  26. #include <resources.h>
  27. #include <toolutils.h>
  28. #include <AppleEvents.h>
  29. #include <EPPC.h>
  30. #include <GestaltEqu.h>
  31. #include <PPCToolbox.h> 
  32. #include <Processes.h>
  33. /* prototypes */
  34. void DoDiskEvents(long dinfo);                              /* hi word is error code, lo word is drive number */
  35. void DrawMain(WindowPtr drawIt);
  36. Boolean DoSelected(long val);
  37. pascal Boolean idleProc(EventRecord *eventIn, long *sleep, RgnHandle *mouseRgn);
  38. void InitAEStuff(void);
  39. void DoHighLevel(EventRecord *AERecord);
  40. void DoDaCall(MenuHandle themenu, long theit);
  41. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  42. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  43. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  44. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  45. pascal OSErr AEReplyHandler(AppleEvent *messagein, AppleEvent *reply, long refIn);
  46. void SendSimple(void);
  47. OSErr FindReciever(AEDesc *theAddress);
  48. #define kSwitchItem 5
  49. #define kReplyItem 7
  50. short gSendInteractArray[4] = 
  51. {
  52.     nil, kAENeverInteract, kAECanInteract, kAEAlwaysInteract, 
  53. };
  54.  
  55.  
  56.  
  57. short replyLevels[] = 
  58. {
  59.     kAENoReply, kAEWaitReply,kAEQueueReply
  60. };
  61.  
  62.  
  63. short replyValue = 0;
  64.  
  65. short gInteract = 1;
  66. short gSwitchLayer = false;
  67. LaunchParamBlockRec launchThis;
  68.  
  69. #define kMBarID 128
  70. #define kAppleMenu 128
  71. #define kFileMenu 129
  72. #define kEditMenu 130
  73. #define kToolsMenu 131
  74. #define kSendButton 128
  75. #define kResumeMask             1       /* bit of message field for resume vs. suspend */
  76. #define kBadCombo 129
  77. #define kNoFind 130
  78. #define kSearch 200
  79. MenuHandle gAppleMenuHandle, gFileMenuHandle, gEditMenuHandle, gToolMenuHandle;
  80. Handle gMymenu;                                             /* my menu bar handle */
  81. ControlHandle sendButton;
  82. struct AEinstalls {
  83.     AEEventClass theClass;
  84.     AEEventID theEvent;
  85.     EventHandlerProcPtr theProc;
  86. };
  87. typedef struct AEinstalls AEinstalls;
  88.  
  89. AEAddressDesc targetAddress;                                /* address of the person to get the data from */
  90.  
  91.  
  92. #define kSimpleEvent 'SIMP'
  93. #define kSimpleClass 'Simp'
  94. Boolean gQuit, gInBackground;
  95. EventRecord gERecord;
  96. AEDesc gTheAddress;
  97. WindowPtr myWindow;
  98. main()
  99. {
  100.     WindowPtr twindow;
  101.     ControlHandle returnedControl;
  102.     MaxApplZone();
  103.     InitGraf((Ptr)&qd.thePort);
  104.     InitFonts();
  105.     InitWindows();
  106.     InitMenus();
  107.     TEInit();
  108.     InitDialogs(nil);
  109.     InitCursor();
  110.     
  111.     InitAEStuff();
  112.     /* set up my menu junk */
  113.     gMymenu = GetNewMBar(kMBarID);
  114.     SetMenuBar(gMymenu);
  115.     gAppleMenuHandle = GetMHandle(kAppleMenu);
  116.     gFileMenuHandle = GetMHandle(kFileMenu);
  117.     gEditMenuHandle = GetMHandle(kEditMenu);
  118.     gToolMenuHandle = GetMHandle(kToolsMenu);
  119.     CheckItem(gToolMenuHandle, gInteract, true);
  120.     CheckItem(gToolMenuHandle, replyValue+kReplyItem, true);
  121.     AddResMenu(gAppleMenuHandle, 'DRVR');
  122.  
  123.     
  124.    
  125.     /* this finds and launches the receiver */
  126.     if(FindReciever(&gTheAddress) != noErr){
  127.         StopAlert(kNoFind,nil);
  128.         ExitToShell();}
  129.     DrawMenuBar();
  130.     myWindow = GetNewWindow(128, nil, (WindowPtr)-1);
  131.     GetNewControl(kSendButton, myWindow);
  132.     do {
  133.         WaitNextEvent(everyEvent, &gERecord, 30, nil);
  134.         switch (gERecord.what) {
  135.             
  136.             case nullEvent:
  137.                 /* no nul processing in this sample */
  138.                 break;
  139.             case updateEvt:
  140.                 DrawMain((WindowPtr)gERecord.message);      /* draw whatever window needs an update */
  141.                 break;
  142.             case mouseDown:
  143.                 /* first see where the hit was */
  144.                 switch (FindWindow(gERecord.where, &twindow)) {
  145.                     
  146.                     case inDesk:                            /* if they hit in desk, then the process manager */
  147.                         break;                              /* will switch us out, we don't need to do anything */
  148.                     case inMenuBar:
  149.                         DoSelected(MenuSelect(gERecord.where));
  150.                         break;
  151.                         
  152.                     case inSysWindow:
  153.                         /* pass to the system */
  154.                         SystemClick(&gERecord, twindow);
  155.                         break;
  156.                     case inContent:
  157.                         GlobalToLocal(&gERecord.where);
  158.                         /* track my button as needed */
  159.                         if (FindControl(gERecord.where, twindow, &returnedControl)) {
  160.                             if (TrackControl(returnedControl, gERecord.where, nil)) {
  161.                                 SendSimple();
  162.                             }
  163.                         }
  164.                         break;
  165.                     case inDrag:
  166.                         if (twindow == FrontWindow())
  167.                             DragWindow(twindow, gERecord.where, &qd.screenBits.bounds);
  168.                         break;
  169.                     case inGrow:
  170.                     case inGoAway:
  171.                         /* don't care */
  172.                         break;
  173.                         
  174.                 }
  175.             case mouseUp:
  176.                 /* don't care */
  177.                 break;
  178.                 /* same action for key or auto key */
  179.             case keyDown:
  180.             case autoKey:
  181.                 if (gERecord.modifiers & cmdKey)
  182.                     DoSelected(MenuKey(gERecord.message & charCodeMask));
  183.                 break;
  184.             case keyUp:
  185.                 /* don't care */
  186.                 break;
  187.             case diskEvt:
  188.                 /* I don't do anything special for disk events, this just passes them */
  189.                 /* to a function that checks for an error on the mount */
  190.                 DoDiskEvents(gERecord.message);
  191.                 break;
  192.             case activateEvt:
  193.                 if (gERecord.modifiers & activeFlag)
  194.                     DrawMain((WindowPtr)gERecord.message);
  195.                 break;
  196.             case networkEvt:
  197.                 /* don't care */
  198.                 break;
  199.             case driverEvt:
  200.                 /* don't care */
  201.                 break;
  202.             case app4Evt:
  203.                 switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  204.                     case suspendResumeMessage:              /* suspend/resume is also an activate/deactivate */
  205.                         gInBackground = (gERecord.message & kResumeMask) == 0;
  206.                         break;
  207.                 }
  208.                 break;
  209.             default:
  210.                 break;
  211.                 /* This dispatches high level events (AppleEvents, for example) */
  212.                 /* to our dispatch routine.  This is NEW in the event loop for */
  213.                 /* System 7 */
  214.             case kHighLevelEvent:
  215.                 DoHighLevel(&gERecord);
  216.                 break;
  217.                 
  218.         }
  219.     } while (gQuit != true);
  220.     
  221.     
  222. }
  223.  
  224. /* DoDaCall opens the requested DA.  It's here as a seperate routine if you'd */
  225. /* like to perform some action or just know when a DA is opened in your */
  226. /* layer.  Can be handy to track memory problems when a DA is opened */
  227. /* with an Option-open */
  228. void DoDaCall(MenuHandle themenu, long theit)
  229. {
  230.     long qq;
  231.     char DAname[255];
  232.     GetItem(themenu, theit, &DAname);
  233.     qq = OpenDeskAcc(DAname);
  234. }
  235.  
  236. /* end DoDaCall */
  237.  
  238. /* DoDiskEvents just checks the error code from the disk mount, */
  239. /* and puts up the 'Format' dialog (through DIBadMount) if need be */
  240. /* You can do much more here if you care about what disks are */
  241. /* in the drive */
  242. void DoDiskEvents(long dinfo)                               /* hi word is error code, lo word is drive number */
  243. {
  244.     short hival, loval, tommy;
  245.     Point fredpoint =  {
  246.         40, 40
  247.     };
  248.     hival = HiWord(dinfo);
  249.     loval = LoWord(dinfo);
  250.     if (hival != noErr)                                     /* something happened */ {
  251.         tommy = DIBadMount(fredpoint, dinfo);
  252.     }
  253. }
  254.  
  255. /* draws my window.  Pretty simple */
  256. void DrawMain(WindowPtr drawIt)
  257. {
  258.     BeginUpdate(drawIt);
  259.     SetPort(drawIt);
  260.     DrawControls(drawIt);
  261.     EndUpdate(drawIt);
  262. }
  263.  
  264. /* my menu action taker.  It returns a Boolean which I usually ignore, but it */
  265. /* mught be handy someday */
  266. Boolean DoSelected(long val)
  267. {
  268.     short loval, hival;
  269.     Boolean temp = false;
  270.     short tempActionOut;
  271.     loval = LoWord(val);
  272.     hival = HiWord(val);
  273.     
  274.     switch (hival) {                                        /* switch off the menu number selected */
  275.         case kAppleMenu:                                    /* Apple menu */
  276.             if (loval != 1) {                               /* if this was not About, it's a DA */
  277.                 DoDaCall(gAppleMenuHandle, loval);
  278.             } else {
  279.                 Alert(128, nil);                            /* do about box */
  280.             }
  281.             break;
  282.         case kFileMenu:                                     /* File menu */
  283.             gQuit = true;                                   /* only  item */
  284.             break;
  285.         case kEditMenu:
  286.             /* edit menu junk */
  287.             /* don't care */
  288.             break;
  289.             /* This is the interaction level menu, sets checks and variables */
  290.         case kToolsMenu:
  291.             if (loval == kSwitchItem) {
  292.                 gSwitchLayer ? gSwitchLayer = false : gSwitchLayer = kAECanSwitchLayer;
  293.                 CheckItem(gToolMenuHandle, kSwitchItem, gSwitchLayer);
  294.             } else {
  295.                 if (loval >= kReplyItem) {
  296.                     if(loval != replyValue){
  297.                     
  298.                     CheckItem(gToolMenuHandle, replyValue+kReplyItem, false);
  299.                     CheckItem(gToolMenuHandle,loval,true);
  300.                     replyValue = loval - kReplyItem;}
  301.                 } else {
  302.                     if (gInteract != loval) {
  303.                         CheckItem(gToolMenuHandle, gInteract, false);
  304.                         CheckItem(gToolMenuHandle, loval, true);
  305.                         gInteract = loval;
  306.                     }
  307.                 }
  308.             }
  309.             break;
  310.     }
  311.     HiliteMenu(0);
  312. }
  313.  
  314. /* InitAEStuff installs my appleevent handlers */
  315. void InitAEStuff(void)
  316. {
  317.     static AEinstalls HandlersToInstall[] =  {
  318.         {
  319.             kCoreEventClass, kAEOpenApplication, AEOpenHandler
  320.         },  {
  321.             kCoreEventClass, kAEOpenDocuments, AEOpenDocHandler
  322.         },  {
  323.             kCoreEventClass, kAEQuitApplication, AEQuitHandler
  324.         },  {
  325.             kCoreEventClass, kAEPrintDocuments, AEPrintHandler
  326.         },
  327.         /* The above are the four required AppleEvents. */
  328.         {    kCoreEventClass, kAEAnswer, AEReplyHandler}
  329.     };
  330.     
  331.     OSErr aevtErr = noErr;
  332.     long aLong = 0;
  333.     Boolean gHasAppleEvents = false;
  334.     /* Check this machine for AppleEvents.  If they are not here (ie not 7.0)
  335.     *   then we exit */
  336.     gHasAppleEvents = (Gestalt(gestaltAppleEventsAttr, &aLong) == noErr);
  337.     /* The following series of calls installs all our AppleEvent Handlers.
  338.     *   These handlers are added to the application event handler list that 
  339.     *   the AppleEvent manager maintains.  So, whenever an AppleEvent happens
  340.     *   and we call AEProcessEvent, the AppleEvent manager will check our
  341.     *   list of handlers and dispatch to it if there is one.
  342.     */
  343.     if (gHasAppleEvents) {
  344.         register qq;
  345.         for (qq = 0; qq < ((sizeof(HandlersToInstall) / sizeof(AEinstalls))); qq++) {
  346.             aevtErr = AEInstallEventHandler(HandlersToInstall[qq].theClass, HandlersToInstall[qq].theEvent,
  347.                                             HandlersToInstall[qq].theProc, 0, false);
  348.             if (aevtErr) {
  349.                 ExitToShell();                              /* just fail, baby */
  350.             }
  351.         }
  352.     } else {
  353.         ExitToShell();
  354.     }
  355. }
  356.  
  357. /* end InitAEStuff */
  358. /* I'm not doing error handling in this sample for clarities sake, you should. Hah, */
  359. /* easy for me to say, huh? */
  360. void DoHighLevel(EventRecord *AERecord)
  361. {
  362.     
  363.     AEProcessAppleEvent(AERecord);
  364.     
  365. }
  366.  
  367. /* end DoHighLevel */
  368.  
  369. /* This is the standard Open Application event.  */
  370. pascal OSErr AEOpenHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  371. {
  372. #pragma unused (messagein,reply,refIn)
  373.     /* we of course don't do anything here in this simple app */
  374.     return(noErr);
  375. }
  376.  
  377. /* end AEOpenHandler */
  378.  
  379. /* Open Doc, opens our documents.  Remember, this can happen at application start AND */
  380. /* anytime else.  If your app is up and running and the user goes to the desktop, hilites one */
  381. /* of your files, and double-clicks or selects Open from the finder File menu this event */
  382. /* handler will get called. Which means you don't do any initialization of globals here, or */
  383. /* anything else except open then doc.  */
  384. /* SO-- Do NOT assume that you are at app start time in this */
  385. /* routine, or bad things will surely happen to you. */
  386.  
  387. pascal OSErr AEOpenDocHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  388. {
  389. #pragma unused (reply, refIn)
  390.     /* we of course don't do anything here */
  391.     return(errAEEventNotHandled);                           /* we have no docs, so no odoc events should come to us */
  392. }
  393.  
  394. pascal OSErr AEPrintHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  395. {                                                           /* no printing handler in yet, so we'll ignore this */
  396.     /* the operation is functionally identical to the ODOC event, with the additon */
  397.     /* of calling your print routine.  */
  398. #pragma unused (reply,refIn)
  399.     /* we of course don't do anything here */
  400.     return(errAEEventNotHandled);                           /* we have no docs, so no pdoc events should come to us */
  401. }
  402.  
  403. /* Standard Quit event handler, to handle a Quit event from the Finder, for example.  */
  404. /* ••••• DO NOT CALL EXITTOSHELL HERE ••••• or you will never have a happy life.  */
  405. pascal OSErr AEQuitHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  406. {
  407. #pragma unused (messagein,refIn)
  408.     
  409.     /* prepQuit sets the Stop flag for us.  It does _NOT_ quit, you */
  410.     /* should NEVER quit from an AppleEvent handler.  Calling */
  411.     /* ExitToShell here would blow things up */
  412.     gQuit = true;
  413.     return(noErr);
  414. }
  415. /* ReplyHandler is used when I've used QueueReply, which means that the */
  416. /* reply will come in through my event loop */
  417. pascal OSErr AEReplyHandler(AppleEvent *messagein, AppleEvent *reply, long refIn)
  418. {
  419. #pragma unused (messagein,refIn)
  420. return(noErr);
  421. }
  422. /* SendSimple sends our simple event.  About simplest demo of an AESEnd */
  423. void SendSimple(void)
  424. {
  425.     AppleEvent ourEvent,ourReply;
  426.     short sendIt = 2;
  427.     AECreateAppleEvent(kSimpleClass, kSimpleEvent, &gTheAddress, kAutoGenerateReturnID, kAnyTransactionID, &ourEvent);
  428.     if (replyLevels[replyValue] == kAEWaitReply && !gSwitchLayer) {
  429.         sendIt = StopAlert(kBadCombo, nil);
  430.     }
  431.     if (sendIt == 2) {
  432.         AESend(&ourEvent, &ourReply, (gSendInteractArray[gInteract] + gSwitchLayer) + replyLevels[replyValue], kAENormalPriority,
  433.                kAEDefaultTimeout,(IdleProcPtr)idleProc, nil);
  434.     }
  435.     AEDisposeDesc(&ourEvent);
  436.     if(replyLevels[replyValue] == kAEWaitReply)AEDisposeDesc(&ourReply);
  437. }
  438.  
  439. /* I'm just launching it, not searching for a port */
  440. /* I use PBCatSearch to search for it's creator and file type. */
  441. OSErr FindReciever(AEDesc *theAddress)
  442. {
  443.     OSErr myError;
  444.     DialogPtr search = GetNewDialog(kSearch,nil,(WindowPtr)-1);
  445.     CSParamPtr csBlockPtr = NewPtrClear(sizeof(CSParam));
  446.     long dirIDUnused;
  447.     Str32 nulString = "\p";
  448.     /* initialize the parameter block */
  449.     DrawDialog(search);
  450.     if (csBlockPtr) {
  451.         csBlockPtr->ioSearchInfo1 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  452.         csBlockPtr->ioSearchInfo2 = (CInfoPBPtr)NewPtrClear(sizeof(CInfoPBRec));
  453.         if (csBlockPtr->ioSearchInfo1 && csBlockPtr->ioSearchInfo2) {
  454.             csBlockPtr->ioMatchPtr = (FSSpecPtr)NewPtrClear(sizeof(FSSpec) * 1);        /* only looking for 1 */
  455.             if (csBlockPtr->ioMatchPtr) {
  456.                 /* Now see if we can create an optimization buffer */
  457.                 csBlockPtr->ioOptBuffer = NewPtr(2048);
  458.                 if (csBlockPtr->ioOptBuffer)
  459.                     csBlockPtr->ioOptBufSize = 2048;
  460.                 else
  461.                     csBlockPtr->ioOptBufSize = 0;           /* no buffer, sorry */
  462.                 csBlockPtr->ioReqMatchCount = 1;
  463.                 csBlockPtr->ioSearchTime = 0;               /* no timeout */
  464.             }
  465.         }
  466.     }
  467.     HGetVol(nil, &csBlockPtr->ioVRefNum, &dirIDUnused);     /* get default volume for search */
  468.     csBlockPtr->ioSearchInfo1->hFileInfo.ioNamePtr = nil;
  469.     csBlockPtr->ioSearchInfo2->hFileInfo.ioNamePtr = nil;
  470.     csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdCreator = 'MuuB';
  471.     csBlockPtr->ioSearchInfo1->hFileInfo.ioFlFndrInfo.fdType = 'APPL';
  472.     csBlockPtr->ioSearchBits = fsSBFlFndrInfo;
  473.     csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdCreator = 0xFFFFFFFF;
  474.     csBlockPtr->ioSearchInfo2->hFileInfo.ioFlFndrInfo.fdType = 0xFFFFFFFF;
  475.     
  476.     myError = PBCatSearch(csBlockPtr, false);               /* search sync */
  477.     if (myError == noErr && csBlockPtr->ioActMatchCount != 0) {
  478.         /* we found it, so launch it */
  479.         
  480.         launchThis.launchBlockID = extendedBlock;
  481.         launchThis.launchEPBLength = extendedBlockLen;
  482.         launchThis.launchFileFlags = nil;
  483.         launchThis.launchControlFlags = launchContinue + launchNoFileFlags + launchDontSwitch;
  484.         launchThis.launchAppSpec = &csBlockPtr->ioMatchPtr[0];
  485.         myError = LaunchApplication(&launchThis);
  486.         if (myError == noErr) {
  487.             /* it launched fine.  we can use the PSN to make a target */
  488.             AECreateDesc(typeProcessSerialNumber, (Ptr)&launchThis.launchProcessSN, sizeof(ProcessSerialNumber), theAddress);
  489.             
  490.         }
  491.     }
  492.     
  493.     /* no matter what happened, kill the memory we had allocated */
  494.     if (csBlockPtr) {
  495.         if (csBlockPtr->ioSearchInfo1)
  496.             DisposPtr((Ptr)csBlockPtr->ioSearchInfo1);
  497.         if (csBlockPtr->ioSearchInfo2)
  498.             DisposPtr((Ptr)csBlockPtr->ioSearchInfo2);
  499.         if (csBlockPtr->ioMatchPtr)
  500.             DisposPtr((Ptr)csBlockPtr->ioMatchPtr);
  501.         if (csBlockPtr->ioOptBuffer)
  502.             DisposPtr((Ptr)csBlockPtr->ioOptBuffer);
  503.         DisposPtr((Ptr)csBlockPtr);
  504.     }
  505.     
  506.     /* catsearch section end */
  507.     DisposDialog(search);
  508.     return(myError);
  509. }
  510. /* My IdleProc for AESend */
  511. pascal Boolean idleProc(EventRecord *eventIn, long *sleep, RgnHandle *mouseRgn)
  512. {
  513.     switch (eventIn->what) {
  514.         case nullEvent:
  515.             /* no nul processing in this sample */
  516.             *sleep = 0;
  517.             mouseRgn = nil;
  518.             break;
  519.         case updateEvt:
  520.         case activateEvt:
  521.             DrawMain((WindowPtr)eventIn->message);          /* draw whatever window needs an update */
  522.             break;
  523.         case app4Evt:
  524.             switch ((gERecord.message >> 24) & 0x0FF) {     /* high byte of message */
  525.                 case suspendResumeMessage:                  /* suspend/resume is also an activate/deactivate */
  526.                     gInBackground = (gERecord.message & kResumeMask) == 0;
  527.                     break;
  528.             }
  529.             break;
  530.             
  531.             
  532.             
  533.     }
  534. return(false);    /* I'll wait forever */
  535. }
  536.